package pl.edu.mimuw.irs.rcp.controller.editor.workflow.part;

import java.util.LinkedHashMap;
import java.util.Map;

import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;

import pl.edu.mimuw.irs.core.model.design.net.IRSRequirement;
import pl.edu.mimuw.irs.core.model.design.net.IRSWorkflow;
import pl.edu.mimuw.irs.core.model.design.resource.Requirement;
import pl.edu.mimuw.irs.core.model.design.resource.Role;
import pl.edu.mimuw.irs.core.model.design.resource.RoleInstance;
import pl.edu.mimuw.irs.core.model.petrinet.Net;
import pl.edu.mimuw.irs.core.util.Converter;
import pl.edu.mimuw.irs.rcp.controller.editor.util.command.AddMemberCommand;
import pl.edu.mimuw.irs.rcp.util.MessageCode;
import pl.edu.mimuw.irs.rcp.util.UITexts;
import pl.edu.mimuw.irs.rcp.util.enums.EnumFont;
import pl.edu.mimuw.irs.rcp.view.figure.FigureWrapper;
import pl.edu.mimuw.irs.rcp.view.figure.IRSRequirementShape;

/**
 * @author Jakub Rauch
 * Created on: 2009-05-21
 */
public class IRSRequirementEditPart extends IRSPlaceEditPart implements EditPart {

	// *** Attributes
	
	public NodePropertySource getPropertySource() {
		if (propertySource == null) {
			propertySource = new RequirementPropertySource(
					Converter.asIRSRequirement(getIRSNode()));
		}
		return propertySource;
	}
	
	// *** Methods

	protected NodeShape getNodeShape() {
		return NodeShape.IRSREQUIREMENT;
	}
	
	public IRSRequirement getIRSRequirement() {
		return Converter.asIRSRequirement(getNode());
	}
	
	public void attachRequirement(String roleName) {
		Net net = null;// FIXME getIRSRequirement().getNet();
		if (net == null) return;
		if (!(net instanceof IRSWorkflow)) return;
		IRSWorkflow irsWorkflow = (IRSWorkflow) net;
		Role role = irsWorkflow.getRole(roleName);
		if (role == null) return;
		attachRequirement(role);
	}
	
	public void attachRequirement(Role role) {
		IRSRequirement irsRequirement = Converter.asIRSRequirement(getNode());
		Requirement requirement = new Requirement();
		Command addRequirement = new AddMemberCommand(irsRequirement.getRequirements(), requirement);
		RoleInstance roleInstance = new RoleInstance(role);
		Command addRoleInstance = new AddMemberCommand(requirement, roleInstance);
		CompoundCommand compound = new CompoundCommand();
		compound.add(addRequirement);
		compound.add(addRoleInstance);
		getViewer().getEditDomain().getCommandStack().execute(compound);
		
		refresh();
	}

	public void attachRequirement(Requirement requirement) {
		IRSRequirement irsRequirement = Converter.asIRSRequirement(getNode());
		Command addRequirement = new AddMemberCommand(irsRequirement.getRequirements(), requirement.copy());
		getViewer().getEditDomain().getCommandStack().execute(addRequirement);
		
		refresh();
	}
	
	@Override
	protected void refreshVisuals() {
		super.refreshVisuals();
		
		IRSRequirement irsRequirement = Converter.asIRSRequirement(getNode());
		FigureWrapper wrapper = (FigureWrapper)getFigure();
		
		if (!irsRequirement.getRequirements().isEmpty()) {
			wrapper.getLabel().setFont(EnumFont.ARIAL_8_BOLD.getInstance());
			IRSRequirementShape shape = (IRSRequirementShape) wrapper.getFigure();
			shape.setEmpty(false);
		} else {
			wrapper.getLabel().setFont(EnumFont.ARIAL_8.getInstance());
			IRSRequirementShape shape = (IRSRequirementShape) wrapper.getFigure();
			shape.setEmpty(true);
		}	
	}
	
	// *** Inner classes
	
	public class RequirementPropertySource extends NodePropertySource {

		protected static final String PROPERTY_TIME_MEAN = "properties.requirement.time.mean";
		protected static final String PROPERTY_TIME_DEVIATION = "properties.requirement.time.deviation";
		
		// *** Attributes
		
		private IRSRequirement requirement;
		public IRSRequirement getRequirement() {
			return requirement;
		}
		
		private int orgTimeUnits;
		private double orgDeviation;
		
		private IPropertyDescriptor[] propertyDescriptors;
		private Map<String, Requirement> requirementsMap;
		public Map<String, Requirement> getRequirementsMap() {
			if (requirementsMap == null) 
				requirementsMap = new LinkedHashMap<String, Requirement>();
			return requirementsMap;
		}
		
		// *** Constructors
		
		public RequirementPropertySource(IRSRequirement requirement) {
			super(requirement);
			this.requirement = requirement;
			this.orgTimeUnits = requirement.getTimeUnits();
			this.orgDeviation = requirement.getDeviation();
		}
		
		// *** Methods
		
		@Override
		public IPropertyDescriptor[] getPropertyDescriptors() {
			if (propertyDescriptors == null) {
				IPropertyDescriptor[] superPropertyDescriptors = super.getPropertyDescriptors();

				// Time cost descriptor
				PropertyDescriptor propertyDescriptorMean = new TextPropertyDescriptor(PROPERTY_TIME_MEAN, 
						UITexts.get(MessageCode.PROPERTIES_FIELD_COST_TIME_MEAN));
				propertyDescriptorMean.setCategory(UITexts.get(MessageCode.PROPERTIES_CATEGORY_COST_TIME));
				PropertyDescriptor propertyDescriptorDeviation = new TextPropertyDescriptor(PROPERTY_TIME_DEVIATION, 
						UITexts.get(MessageCode.PROPERTIES_FIELD_COST_TIME_DEVIATION));
				propertyDescriptorDeviation.setCategory(UITexts.get(MessageCode.PROPERTIES_CATEGORY_COST_TIME));
				
	            propertyDescriptors = 
	            	new IPropertyDescriptor[superPropertyDescriptors.length + 2];
	            
	            System.arraycopy(superPropertyDescriptors, 0, 
	            		propertyDescriptors, 0, superPropertyDescriptors.length);
	            propertyDescriptors[superPropertyDescriptors.length] = propertyDescriptorMean;
	            propertyDescriptors[superPropertyDescriptors.length + 1] = propertyDescriptorDeviation;
            }
            return propertyDescriptors;
		}

		@Override
		public Object getPropertyValue(Object id) {
			if (PROPERTY_TIME_MEAN.equals(id)) {
				return String.valueOf(requirement.getTimeUnits());
			} else if (PROPERTY_TIME_DEVIATION.equals(id)) {
				return String.valueOf(requirement.getDeviation());
			}
			return super.getPropertyValue(id);
		}

		@Override
		public boolean isPropertySet(Object id) {
			if (PROPERTY_TIME_MEAN.equals(id)) {
	        	String curValue = (String)getPropertyValue(id);
				return !curValue.equals(String.valueOf(this.orgTimeUnits));
			} else if (PROPERTY_TIME_DEVIATION.equals(id)) {
	        	String curValue = (String)getPropertyValue(id);
				return !curValue.equals(String.valueOf(this.orgDeviation));
			}
			return super.isPropertySet(id);
		}

		@Override
		public void resetPropertyValue(Object id) {
			if (PROPERTY_TIME_MEAN.equals(id)) {
				setPropertyValue(id, String.valueOf(this.orgTimeUnits));
			} else if (PROPERTY_TIME_DEVIATION.equals(id)) {
				setPropertyValue(id, String.valueOf(this.orgDeviation));
			}
			super.resetPropertyValue(id);
		}

		@Override
		public void setPropertyValue(Object id, Object value) {
			if (PROPERTY_TIME_MEAN.equals(id)) {
				try {
					requirement.setTimeUnits(Integer.valueOf((String)value));
				} catch (NumberFormatException nfe) {}
			} else if (PROPERTY_TIME_DEVIATION.equals(id)) {
				try {
					requirement.setDeviation(Double.valueOf((String)value));
				} catch (NumberFormatException nfe) {}
			}
			super.setPropertyValue(id, value);
		}
		
	}
}
